/*
 * Copyright (C) 2008 by The Regents of the University of California
 * Redistribution of this file is permitted under the terms of the GNU
 * Public License (GPL).
 *
 * @author Junghoo "John" Cho <cho AT cs.ucla.edu>
 * @date 5/28/2008
 */

#ifndef BTNODE_H
#define BTNODE_H
#define MAX_LEAF (1008/(3*sizeof(int)))-2 //max should be 84 
#define MAX_NONLEAF (1008/(2*sizeof(int)))-2 //max should be 126

#define GREATER_SATISFIED -1000
#define LESS_SATISFIED -1001
#define GREATEREQUAL_SATISFIED -1002
#define LESSEQUAL_SATISFIED -1003
#define INEQUALITY_NOT_SATISFIED -1004
#define EQUALITY_NOT_SATISFIED -1005
#define EQUALITY_SATISFIED -1006

#include <stdlib.h>
#include <stdio.h>
#include "RecordFile.h"
#include "PageFile.h"
#include <map.h>

/**
 * Hash Map:
 * Map in memory. 
 * Need to store this to disk.
 */
map<PageId, string> hashmap;

/**
 * BTLeafNode: The class representing a B+tree leaf node.
 */
class BTLeafNode {
  public:
      
      char* getBuffer()
      {
          return buffer;
      }
      
      void setBuffer(char *buf)
      {
          buffer = buf;
      }
      
      BTLeafNode(PageId, PageId, PageId);
      
   /**
    * Insert the (key, rid) pair to the node.
    * Remember that all keys inside a B+tree node should be kept sorted.
    * @param key[IN] the key to insert
    * @param rid[IN] the RecordId to insert
    * @return 0 if successful. Return an error code if the node is full.
    */
    static int insert(int key, const RecordId& rid, PageFile &pf, PageId rootPid);

    /**
     * LeafSort
     * @param key
     * @param rid
     * @param sibling
     * @param siblingKey
     * @return 
     */
    static RC leafSort(void *);
    
    static void leafSwap(void *, int, int);
    
   /**
    * Insert the (key, rid) pair to the node
    * and split the node half and half with sibling.
    * The first key of the sibling node is returned in siblingKey.
    * Remember that all keys inside a B+tree node should be kept sorted.
    * @param key[IN] the key to insert.
    * @param rid[IN] the RecordId to insert.
    * @param sibling[IN] the sibling node to split with. This node MUST be EMPTY when this function is called.
    * @param siblingKey[OUT] the first key in the sibling node after split.
    * @return 0 if successful. Return an error code if there is an error.
    */
    //RC insertAndSplit(int key, const RecordId& rid, BTLeafNode& sibling, int& siblingKey);
    static RC insertAndSplit(int prevNodeCount, int &parentid, int newNodeCount, int newNodeId, BTLeafNode newSplitNode,
        void *nodeToInsert_buffer, int cursor, PageFile &pf);
   /**
    * Find the index entry whose key value is larger than or equal to searchKey
    * and output the eid (entry id) whose key value &gt;= searchKey.
    * Remember that keys inside a B+tree node are sorted.
    * @param searchKey[IN] the key to search for.
    * @param eid[OUT] the entry number that contains a key larger              
    *                 than or equalty to searchKey.
    * @return 0 if successful. Return an error code if there is an error.
    */
    static RC locate(int searchKey, int& eid, PageId pid, PageFile &pf, int op);

   /**
    * Read the (key, rid) pair from the eid entry.
    * @param eid[IN] the entry number to read the (key, rid) pair from
    * @param key[OUT] the key from the slot
    * @param rid[OUT] the RecordId from the slot
    * @return 0 if successful. Return an error code if there is an error.
    */
    static RC readEntry(int eid, int& key, RecordId& rid, PageId pid, PageFile pf);

   /**
    * Return the pid of the next slibling node.
    * @return the PageId of the next sibling node 
    */
    PageId getNextNodePtr();


   /**
    * Set the next slibling node PageId.
    * @param pid[IN] the PageId of the next sibling node 
    * @return 0 if successful. Return an error code if there is an error.
    */
    RC setNextNodePtr(PageId pid);

   /**
    * Return the number of keys stored in the node.
    * @return the number of keys in the node
    */
    int getKeyCount();
 
   /**
    * Read the content of the node from the page pid in the PageFile pf.
    * @param pid[IN] the PageId to read
    * @param pf[IN] PageFile to read from
    * @return 0 if successful. Return an error code if there is an error.
    */
    RC read(PageId pid, const PageFile& pf);
    
   /**
    * Write the content of the node to the page pid in the PageFile pf.
    * @param pid[IN] the PageId to write to
    * @param pf[IN] PageFile to write to
    * @return 0 if successful. Return an error code if there is an error.
    */
    RC write(PageId pid, PageFile& pf);

  private:
   /**
    * The main memory buffer for loading the content of the disk page 
    * that contains the node.
    */
    char buffer[PageFile::PAGE_SIZE];
    struct{
        int key;
        RecordId recid;
    }Entry[MAX_LEAF];
    

    int numkeys;
}; 


/**
 * BTNonLeafNode: The class representing a B+tree nonleaf node.
 */
class BTNonLeafNode {
  public:
      /**
       * Constructor
       * @param key
       * @param pid
       * @return 
       */
   BTNonLeafNode(PageId ppid, PageId pid);

   char* getBuffer()
   {
      return buffer;
   }

   
   /**
    * Insert a (key, pid) pair to the node.
    * Remember that all keys inside a B+tree node should be kept sorted.
    * @param key[IN] the key to insert
    * @param pid[IN] the PageId to insert
    * @return 0 if successful. Return an error code if the node is full.
    */
    static int insert(int key_above, PageId newNodeId, PageId parentid, PageFile &pf);

   /**
    * Insert the (key, pid) pair to the node
    * and split the node half and half with sibling.
    * The sibling node MUST be empty when this function is called.
    * The middle key after the split is returned in midKey.
    * Remember that all keys inside a B+tree node should be kept sorted.
    * @param key[IN] the key to insert
    * @param pid[IN] the PageId to insert
    * @param sibling[IN] the sibling node to split with. This node MUST be empty when this function is called.
    * @param midKey[OUT] the key in the middle after the split. This key should be inserted to the parent node.
    * @return 0 if successful. Return an error code if there is an error.
    */
    static RC insertAndSplit(PageId pid, PageFile &pf, PageId &rootPid);

   /**
    * Given the searchKey, find the child-node pointer to follow and
    * output it in pid.
    * Remember that the keys inside a B+tree node are sorted.
    * @param searchKey[IN] the searchKey that is being looked up.
    * @param pid[OUT] the pointer to the child node to follow.
    * @return 0 if successful. Return an error code if there is an error.
    */
    static RC locateChildPtr(int searchKey, PageId& pid, PageFile &pf);

   /**
    * Initialize the root node with (pid1, key, pid2).
    * @param pid1[IN] the first PageId to insert
    * @param key[IN] the key that should be inserted between the two PageIds
    * @param pid2[IN] the PageId to insert behind the key
    * @return 0 if successful. Return an error code if there is an error.
    */
    RC initializeRoot(PageId pid1, int key, PageId pid2);

   /**
    * Return the number of keys stored in the node.
    * @return the number of keys in the node
    */
    int getKeyCount();

   /**
    * Read the content of the node from the page pid in the PageFile pf.
    * @param pid[IN] the PageId to read
    * @param pf[IN] PageFile to read from
    * @return 0 if successful. Return an error code if there is an error.
    */
    RC read(PageId pid, const PageFile& pf);
    
   /**
    * Write the content of the node to the page pid in the PageFile pf.
    * @param pid[IN] the PageId to write to
    * @param pf[IN] PageFile to write to
    * @return 0 if successful. Return an error code if there is an error.
    */
    RC write(PageId pid, PageFile& pf);
    
    /**
     * Leaf - Sort
     */
    static RC nonLeafSort(void *buff);
    
    static void nonLeafSwap(void *, int, int);

    
    
    
  private:
   /**
    * The main memory buffer for loading the content of the disk page 
    * that contains the node.
    */
    char buffer[PageFile::PAGE_SIZE];
    int numkeys;
    
    
}; 

#endif /* BTNODE_H */
